#include <sys/types.h>
#include <sys/socket.h>						/*包含socket()/bind()*/
#include <netinet/in.h>						/*包含struct sockaddr_in*/
#include <string.h>							/*包含memset()*/
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
#define PORT_SERV 8888/*服务器端口*/
#define BUFF_LEN 256									/*缓冲区大小*/
#define PACKET_SEQ 2000
#define LENGTH 1024
#define SEND_LENGTH 1024+12

#define DATAS_LENGTH 10

// 互斥锁
pthread_mutex_t mute;

struct RecvData {
	// 标识用户
	int userId;
	// 是否结束，1表示结束
	int flag;
	// 数据缓存区
	// char buff[PACKET_SEQ][LENGTH];
	char **buff;
};

// 定义单个用户的结束数据类型
typedef struct RecvData RecvData;

// 定义10个用户存储区
RecvData datas[DATAS_LENGTH];

/**
 * 初始化用户存储区
 * */
void init_datas()
{
	int i;
	for (i = 0; i < DATAS_LENGTH; i++)
	{
		datas[i].userId = 0;
		datas[i].flag = 0;
	}
}

/**
 * 判断datas是否还有空位
 * return 1: 表示还有空位
 * return 0: 表示没有空位了，不能继续添加user
*/
int is_empty()
{
	int i;
	for (i = 0; i < DATAS_LENGTH; i++)
	{
		if (datas[i].userId == 0)
		{
			return 1;
		}
	}
	return 0;
}

/**
 * 判断用户是否已经存在
 * @param userId: 指定用户标识
 * @return 如果存在返回其索引值，否则返回-1
 * */
int user_is_exist(int userId)
{
	int i;
	for (i = 0; i < DATAS_LENGTH; i++)
	{
		if (datas[i].userId == userId)
		{
			// 返回1表示用户存在
			return i;
		}
	}
	return -1;
}

/**
 * 清除已经完成的userData
*/
void clear_datas()
{
	int i;
	for (i = 0; i < DATAS_LENGTH; i++)
	{
		if (datas[i].flag)
		{
			datas[i].userId = 0;
			datas[i].flag = 0;
			free(datas[i].buff);
		}
	}
}

/**
 * 清除datas的某一列
*/
void clear_data(int user_index) 
{
	datas[user_index].userId = 0;
	datas[user_index].flag = 0;
	free(datas[user_index].buff);
}

/**
 * datas添加用户
 * return 1: 表示添加成功
 * return 0: 表示添加失败
*/
int add_user(int userId)
{
	int i;
	for (i = 0; i < DATAS_LENGTH; i++)
	{
		if (datas[i].userId == 0)
		{
			datas[i].userId = userId;
			return 1;
		}
	}
	return 0;
}

/**
 * 给用户添加相关数据包
 * @param user_index: 用户在datas的索引值
 * @param flag: 结束标识
 * @param index: 包的索引值
 * @param data: 数据指针
*/
void user_add_data(int user_index, int flag, int index, char *data)
{
	// 索引值应该减1，因为0号包传递了长度没有数据
	index -= 1;
	if (flag)
	{
		datas[user_index].flag = 1;
	}
	memcpy(datas[user_index].buff[index], data, LENGTH);
}

/**
 * 生成保存文件
 * @param n: 包总共大小
 * @param userId: 用户id
 * @param user_index: 用户占用的data区索引值
*/
void save_file(void *args) 
{
	//上锁，函数是阻塞的
    pthread_mutex_lock(&mute);
	int *arr;
	arr = (int *) args;
	int n = arr[0];
	int userId = arr[1];
	int user_index = arr[2];
	n -= 1;
	printf("保存文件data%d\n", userId);
	char fileName[20];
	sprintf(fileName, "data%d", userId);
	// 新建data文件保存上传文件
	int fd = open(fileName, O_CREAT | O_RDWR, S_IRWXU);
	char temp[LENGTH];
	int i;
	if (fd == -1)
	{
		printf("create file error\n");
		exit(0);
	}
	for (i = 0; i < n; i++)
	{
		bzero(temp, LENGTH);
		// 从buff[i]复制temp长度的字符串到temp中
		memcpy(temp, datas[user_index].buff[i], LENGTH);
		// 写入temp的有效字符串
		write(fd, temp, LENGTH);
	}
	close(fd);
	datas[user_index].flag = 1;
	clear_data(user_index);
	//解锁
    pthread_mutex_unlock(&mute);
}

/**
 * 处理客户端上传的文件
*/
void handle_file(int s, struct sockaddr *client)
{
	int i, j, flag, userId, user_index;
	int index;					/*响应包的索引*/
	char tmp_buff[SEND_LENGTH]; /*接收发送缓冲区															*/
	socklen_t len;				/*地址长度*/
	pthread_t thread1;
	int args[3];

	init_datas();
	while (1)
	{
		memset(tmp_buff, '\0', SEND_LENGTH);
		len = sizeof(*client);
		recvfrom(s, tmp_buff, SEND_LENGTH, 0, client, &len);
		/*接收数据放到buff中，并获得客户端地址*/

		// 数组的命名就是地址
		index = ntohl(*((int *)tmp_buff));
		// 数组成员需要使用&取地址
		flag = ntohl(*((int *)&tmp_buff[4]));
		// 用户标识
		userId = ntohl(*((int *)&tmp_buff[8]));
		// 判断用户id是否已经存在
		if (user_is_exist(userId) == -1)
		{
			// 如果datas没满
			if (is_empty())
			{
				add_user(userId);
			}
			else
			{
				// 直接丢弃
				printf("数据区用户已满\n");
				continue;
			}
		}

		// 返回当前用户所在data的索引值
		user_index = user_is_exist(userId);

		// 如果index等于0，为第一个包时，根据长度动态分配内存空间
		if (!index)
		{
			// 一共flag个包有数据，但第一个包没有数据，所以加1
			flag += 1;
			// 相关内存
			datas[user_index].buff = (char **)malloc(sizeof(char *) * flag);
			for (j = 0; j < flag; j++)
			{
				datas[user_index].buff[j] = (char *)malloc(sizeof(char) * LENGTH);
				memset(datas[user_index].buff[j], '\0', LENGTH);
			}
			printf("用户 %d 的内存分配成功 占用data[%d] 大小为 %dKb\n", userId, user_index, flag);
			continue;
		}

		// 添加用户数据
		user_add_data(user_index, flag, index, &tmp_buff[12]);
		// 判断标识位是否为结束位
		if (flag)
		{
			// 使用进程可能会影响到tmp_buff
			printf("接收到文件 userId=%d, 占用data[%d] 一共 %d 个包\n", userId, user_index, index);
			args[0] = index;
			args[1] = userId;
			args[2] = user_index;
			// 使用线程执行保存文件操作
			pthread_create(&thread1, NULL, (void *)&save_file, (void *)args);
			continue;
		}
	}
}

int main(int argc, char*argv[])
{
	int s;									/*套接字文件描述符*/
	int i;
	pid_t pid[4];
	struct sockaddr_in addr_serv,addr_clie;		/*地址结构*/
	
	s = socket(AF_INET, SOCK_DGRAM, 0);			/*建立数据报套接字*/
	
	memset(&addr_serv, 0, sizeof(addr_serv));		/*清空地址结构*/
	addr_serv.sin_family = AF_INET;				/*地址类型为AF_INET*/
	addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);	/*任意本地地址*/
	addr_serv.sin_port = htons(PORT_SERV);			/*服务器端口*/
	
	bind(s, (struct sockaddr*)&addr_serv, sizeof(addr_serv));
													/*绑定地址*/
	
	handle_file(s, (struct sockaddr*)&addr_clie);	/*回显处理程序*/
	
	
	return 0;	
}
